home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 February / LiquidLibrary 2005 February - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / pdf_font.ps < prev    next >
Text File  |  2003-01-03  |  31KB  |  946 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % pdf_font.ps
  7. % PDF font operations.
  8.  
  9. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  10. .currentglobal true .setglobal
  11. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  12. GS_PDF_ProcSet begin
  13. pdfdict begin
  14.  
  15. % We cache the PostScript font in an additional element of the
  16. % font resource dictionary, called PSFont.
  17.  
  18. % ---------------- Encodings ---------------- %
  19.  
  20. % Apply a list of differences to an Encoding.
  21. % Note that the differences may cause the array to grow.
  22. /updateencoding {    % <encoding> <differences> updateencoding <enc'>
  23.     % Calculate the length of the result.
  24.   exch 0 2 index {
  25.     dup type /nametype ne { exch pop } { pop 1 add } ifelse
  26.   } forall
  27.   1 index length .max array dup 0 4 -1 roll putinterval
  28.   exch 0 exch {
  29.         % Stack: enc' code element
  30.     dup type /nametype ne
  31.       { exch pop }
  32.       { 3 copy put pop 1 add }
  33.     ifelse
  34.   } forall pop
  35. } bdef
  36.  
  37. % Get the Encoding for a font.
  38. /getencoding        % <base-encoding> <font-resource> getencoding <enc>
  39.  { /Encoding knownoget
  40.     { dup type /nametype eq
  41.        { 
  42.          % The published PDF specification says the Encoding name
  43.          % "must be" one of the 3 predefined Encodings, implying
  44.          % that an error should occur if it isn't.  However, Acrobat
  45.          % Reader simply ignores unknown names, and since there are
  46.          % some buggy applications that rely on this, we do the same.
  47.  
  48.          dup dup dup /MacRomanEncoding eq
  49.          exch /MacExpertEncoding eq or 
  50.          exch /WinAnsiEncoding eq or
  51.            { exch pop findencoding
  52.            }
  53.            { pop
  54.            }
  55.          ifelse
  56.        }
  57.        { dup /BaseEncoding knownoget
  58.       { findencoding 3 -1 roll pop exch
  59.       }
  60.      if
  61.      /Differences knownoget { updateencoding } if
  62.        }
  63.       ifelse
  64.     }
  65.    if
  66.  } bdef
  67.  
  68. % Rename a font with a generated name.
  69. /renamefont {        % <fontdict> renamefont <font'>
  70.   dup /FontName 2 copy get genfontname dup 5 1 roll put definefont
  71. } bind def
  72.  
  73. % Adjust a font according to the Encoding and Widths in the font resource.
  74. /adjustfont {        % <font-resource> <font> adjustfont <font'>
  75.   getfontencoding
  76.   getfontmetrics 4 -1 roll pop .updatefont { renamefont } if
  77. } bind def
  78.  
  79. % Get the (possibly modified) encoding of a font.
  80. /getfontencoding {    % <font-resource> <font> getfontencoding
  81.             %   <font-resource> <font> <Encoding|null>
  82.   1 index /Encoding known {
  83.     dup /Encoding .knownget { 2 index getencoding } { null } ifelse
  84.   } {
  85.     null
  86.   } ifelse
  87. } bdef
  88.  
  89. /find_in_diff     % <Differences> <index> find_in_diff <bool>
  90. { false exch 0 4 3 roll
  91.   { dup type /nametype ne { exch pop } { pop 1 add } ifelse
  92.     2 copy eq {
  93.       pop pop pop true 0 0 exit
  94.     } if
  95.   } forall
  96.   pop pop
  97. } bdef
  98.  
  99. % Get the metrics of a font, if specified.
  100. /getfontmetrics {    % <font-resource> <font> <Encoding|null> getfontmetrics
  101.             %   <font-resource> <font> <Encoding|null>
  102.             %   <Metrics|null>
  103.   2 index /Widths known {
  104.     dup null eq { pop dup /Encoding get } if
  105.     4 dict begin
  106.       /Encoding exch def
  107.       /Metrics Encoding length dict def
  108.       exch
  109.       dup /Widths oget /Widths exch def
  110.         % Stack: font font-res
  111.         % Note that widths are always based on a 1000-unit
  112.         % character space, but the FontMatrix may specify
  113.         % some other scale factor.  Compensate for this here,
  114.         % by scaling the Widths if necessary.
  115.       0.001 2 index /FontMatrix get 0 get div
  116.         % Stack: font font-res mscale
  117.       1 index /FirstChar oget dup 1 4 index /LastChar oget
  118.        {    % Stack: font font-res mscale first-char index
  119.      Encoding 1 index get
  120.      Widths 2 index 4 index sub oget
  121.          % Stack: font font-res mscale first-char index charname width
  122.      4 index mul
  123.         % The following 'loop' is only context for 'exit'.
  124.      {    
  125.         % Work around a bug in pdfTeX, which can generate Encoding
  126.         % vectors containing nulls :
  127.        1 index null eq { exit } if
  128.         % There is a hack here to deal with encodings where the
  129.         % same character appears more than once, because the Metrics
  130.         % dictionary works by character name, not by character code.
  131.         % We prefer to take (1) non-zero width, and (2) width for 
  132.         % the character code which appears in Differences.
  133.        Metrics 2 index .knownget not { 0 } if 0 ne {
  134.          5 index /Encoding knownoget not { exit } if
  135.          dup type /dicttype ne { pop exit } if
  136.          /Differences knownoget not { exit } if
  137.          3 index //find_in_diff exec not { exit } if
  138.        } if
  139.        2 copy Metrics 3 1 roll put
  140.        exit
  141.      } loop
  142.      pop pop pop
  143.        }
  144.       for pop
  145.         % Now fill in the MissingWidth for any encoded characters
  146.         % that aren't in Metrics already.  Note that built-in
  147.         % fonts may have Widths/FirstChar/LastChar but no
  148.         % FontDescriptor, so we must check for this.
  149.         % Stack: font font-res mscale
  150.       1 index /FontDescriptor knownoget {
  151.     Metrics exch
  152.     /MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
  153.     Encoding {
  154.         % Stack: font font-res mscale missing-width metrics charname
  155.         % Work around the abovementioned pdfTeX bug.
  156.       dup null ne {
  157.         2 copy known not { 2 copy 4 index put } if pop
  158.       } {
  159.         pop
  160.       } ifelse
  161.     } forall pop pop pop
  162.       } {
  163.     pop
  164.       } ifelse
  165.     exch Encoding Metrics end
  166.   } {
  167.     null
  168.   } ifelse
  169. } bdef
  170.  
  171. currentdict /find_in_diff undef
  172.  
  173. % ---------------- Descriptors ---------------- %
  174.  
  175. % Partial descriptors for the 14 built-in fonts.  Note that
  176. % from PDF 1.1 to PDF 1.2, the meaning of the Flag 6 in the FontDescriptor
  177. % object has undergone a subtle change in its meaning which has serious
  178. % consequences for searching with Acrobat:
  179. % In PDF 1.1, the flag meant: Font has StandardEncoding
  180. % In PDF 1.2, the flag means: Font has (subset of) StandardRomanCharacterSet
  181. /standardfontdescriptors mark
  182.   /Courier mark /Flags 16#23 .dicttomark
  183.   /Courier-Oblique 1 index
  184.   /Courier-Bold 1 index
  185.   /Courier-BoldOblique 1 index
  186.   /Helvetica mark /Flags 16#20 .dicttomark
  187.   /Helvetica-Oblique 1 index
  188.   /Helvetica-Bold 1 index
  189.   /Helvetica-BoldOblique 1 index
  190.   /Times-Roman mark /Flags 16#22 .dicttomark
  191.   /Times-Bold 1 index
  192.   /Times-Italic mark /Flags 16#62 .dicttomark
  193.   /Times-BoldItalic 1 index
  194.   /Symbol mark /Flags 16#4 .dicttomark
  195.   /ZapfDingbats 1 index
  196. .dicttomark readonly def
  197.  
  198. % ---------------- Utilities ---------------- %
  199.  
  200. % Fabricate a font name by adding ?'s on the end.
  201. /genfontname        % <name> genfontname <name>
  202.  { dup length string cvs
  203.     { (?) concatstrings
  204.       dup cvn FontDirectory exch known not { cvn exit } if
  205.     }
  206.    loop
  207.  } bdef
  208.  
  209. % Find a font, and adjust its encoding if necessary.
  210. /.pdfdfndict mark
  211.   /defaultfontname /Helvetica
  212. .dicttomark readonly def
  213. /pdffindfont {        % <font-resource> <fontname> pdffindfont <font>
  214.         % If the font isn't available, synthesize one based on
  215.         % its descriptor.
  216.   dup /Font resourcestatus {
  217.     pop pop findfont
  218.   } {
  219.     1 index /FontDescriptor knownoget {
  220.         % Stack: font-res fontname fontdesc
  221.       dup /Flags oget
  222.       dup 16#40 and -6 bitshift        % 1, oblique/italic
  223.       1 index 16#40000 and -17 bitshift add    % 2, bold
  224.       exch 16#2 and 2 bitshift add    % 8, serif
  225.         % We should look at the fixed flag, too.
  226.         % Stack: font-res fontname fontdesc properties
  227.       1 index /FontName oget exch
  228.         % Analyzes font name and extract "Narrow" property
  229.         % which is not described by the FontDescriptor Flags.
  230.       0 2 index .fontnameproperties 4 and or
  231.         % Rebind the default font name to Helvetica so that
  232.         % fonts with no properties are handled correctly.
  233.       //.pdfdfndict begin .substitutefontname end
  234.         % Stack: font-res fontname fontdesc substname|null
  235.       Fontmap 1 index known not {
  236.         % No available good substitution, use the standard one.
  237.     pop 1 index .substitutefont
  238.       } if
  239.       QUIET not {
  240.     (Substituting font ) print dup =only
  241.     ( for ) print 2 index =only (.) = flush
  242.       } if
  243.       3 -1 roll pop findfont
  244.         % Stack: font-res fontdesc font
  245.         % If this is a small-caps font, replace the CharString
  246.         % entries for a..z.
  247.       exch /Flags oget 16#20000 and 0 ne {
  248.     true .copyfontdict
  249.     dup /CharStrings 2 copy get dup length dict .copydict
  250.     4 index /FirstChar get 97 .max
  251.     5 index /LastChar get 122 .min 1 exch {
  252.         % Stack: font-res font' font' /CharStrings charstrings code
  253.         % Note that this only remaps a-z, not accented characters.
  254.       5 index /Widths oget 1 index 7 index /FirstChar get sub oget
  255.       1 string dup 0 5 -1 roll put
  256.         % Stack: font-res font' font' /CharStrings charstrings code
  257.         %   width (x)
  258.       2 index exch dup cvn exch
  259.       dup 0 2 copy get 32 sub put 4 -1 roll {
  260.             % Stack: operand (X) width
  261.         0 setcharwidth exch pop
  262.         currentfont /FontMatrix get matrix invertmatrix concat
  263.         0.7 dup scale 0 0 moveto show
  264.       } /exec cvx 4 packedarray cvx put
  265.     } for put
  266.     renamefont
  267.       } if
  268.     } {
  269.         % No descriptor available, use the default algorithm.
  270.       findfont
  271.     } ifelse
  272.   } ifelse adjustfont
  273. } bdef
  274.  
  275. % ---------------- Type 1 fonts ---------------- %
  276.  
  277. /buildType1        % <Type1-font-resource> buildType1 <font>
  278.  { dup /BaseFont get pdffindfont
  279.  } bdef
  280.  
  281. % The state dictionary for the embedded Type 1 font reading procedure
  282. % has the following keys and values:
  283. %    data - stream (filter)
  284. %    buffer, buffer2 - string
  285. %    hexify - procedure to convert buffer to hex if needed
  286. %    leftstr - string containing (non-negative) integer
  287. %    sectionstr - string containing a character 0 .. 3
  288. %    stream - (stream) dictionary
  289. %    proc - procedure of the form {-dict- type1read}
  290. %       pfbhdr - string containing 16#80 if PFB, 0 otherwise
  291. % When the procedure is executing, this dictionary is current.
  292. % leftstr and sectionstr are strings so that we can change their values
  293. % reliably in case the font executes a restore!
  294. % We also have to do something special about embedded fonts that
  295. % execute definefont more than once -- that is the function of topFontDict.
  296.  
  297. % Read an embedded Type 1 font.
  298. /readfontfilter {    % <proc> readfontfilter <filter>
  299.   0 () /SubFileDecode filter
  300. } bdef
  301. /readtype1dict 5 dict dup begin
  302.   /definefont {
  303.     dup topFontDict eq topFontDict null eq or {
  304.       dup wcheck not { dup length dict copy } if
  305.       exch pop savedFontName exch
  306.     } if
  307.     //systemdict /definefont get exec
  308.   } bdef
  309.   /eexec {
  310.     % Assume the font dictionary is directly below the file on the stack
  311.     count 0 gt { /topFontDict 2 index cvlit store } if
  312.     55665 /eexecDecode filter
  313.     //systemdict begin readtype1dictcopy begin cvx stopped
  314.     currentdict readtype1dictcopy eq { end } if
  315.     currentdict //systemdict eq { end } if
  316.      { stop } if
  317.   } bdef
  318. end readonly def
  319. /readtype1 {        % <font-resource> <stream-dict> readtype1 <font>
  320.         % Read the definition, using a procedure-based filter
  321.         % that turns binary/hex conversion on and off
  322.         % at the right times.
  323.    1 index exch
  324.    PDFfile fileposition 3 1 roll
  325.    11 dict begin
  326.      /leftstr (          ) 10 string copy def
  327.        dup /Length1 oget leftstr cvs pop
  328.      /sectionstr <00> 1 string copy def
  329.      /pfbhdr <00> 1 string copy def
  330.      /stream 1 index def
  331.      true resolvestream /data exch def
  332.      /buffer 1000 string def        % arbitrary
  333.      /buffer2 buffer length 2.1 div cvi 1 sub string def
  334.      /hexify /buf2hex load def
  335.    currentdict end
  336.    /type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
  337.    readfontfilter
  338.         % Some buggy embedded fonts leave extra junk on the stack,
  339.         % so we have to make a closure that records the stack depth
  340.         % in a fail-safe way.
  341.    //systemdict begin
  342.         % The PDF specification is somewhat muddy about whether
  343.         % an embedded font's name is supposed to be the BaseFont
  344.         % from the Font object or the FontName from the descriptor.
  345.         % Acrobat Distiller requires the former.  Save away the
  346.         % name so we can substitute it at definefont time.
  347.    //readtype1dict dup length 3 add dict copy begin
  348.    1 index /BaseFont oget /savedFontName exch def
  349.    /topFontDict null def
  350.    /readtype1dictcopy currentdict def
  351.     { run } aload pop count 1 sub 2 packedarray cvx exec
  352.    end end
  353.    count exch sub { pop } repeat
  354.    PDFfile 3 -1 roll setfileposition
  355.    /BaseFont oget findfont
  356.    adjustfont
  357.  } bdef
  358.  
  359. % Execute the appropriate reading procedure.
  360. /type1read        % <dict> type1read <string>
  361.  { begin leftstr cvi
  362.     { type1read0 type1read1 type1read2 type1read3 } sectionstr 0 get get exec
  363.    (          ) leftstr copy cvs pop end
  364.  } bdef
  365.  
  366. % Read the next block of data into the buffer.
  367. /type1readdata        % <left> <buffer> type1readdata <substring> <left'>
  368.  { 0 2 index 2 index length min getinterval
  369.         % Adobe requires readstring to signal an error if given
  370.         % an empty string.  Work around this nonsense here.
  371.    dup length 0 ne { data exch readstring pop } if
  372.    dup length 3 -1 roll exch sub
  373.    DEBUG
  374.     { dup =only ( read ) print
  375.       1 index length =only (: ) print
  376.       1 index == flush
  377.     } if
  378.  } bdef
  379.  
  380. % Read the initial byte to see if we need to skip a 6 byte PFB header
  381. /type1read0 {         % <left> type1read0 <string> <left'>
  382.   sectionstr 0 1 put    % either way we go to the next stage
  383.   pfbhdr type1readdata
  384.   1 index 0 get 16#80 eq {
  385.     (\n   **** Warning: Embedded Type1 font in PFB format is not valid PDF.)
  386.     pdfformaterror
  387.     DEBUG { (skipping PFB header) = flush } if
  388.     exch pop buffer 0 5 getinterval type1readdata exch
  389.     dup 4 get 256 mul 1 index 3 get add 256 mul
  390.     1 index 2 get add 256 mul 1 index 1 get add
  391.     DEBUG { (PFB segment length = ) print dup = } if
  392.     exch pop  % discard the string keeping the PFB segment length
  393.     2 copy ne {
  394.       (\n   **** Warning: Type 1 PFB segment length and Length 1 value do not match.)
  395.       pdfformaterror
  396.       exch     % keep the PFB length instead
  397.     } if
  398.     pop
  399.     buffer type1readdata    % go ahead and read a block
  400.   }
  401.   if    % if not PFB, return pfbhdr string (first char of file, usually %).
  402. } bdef
  403.  
  404. % Read the next block of the initial text portion.
  405. /type1read1 {        % <left> type1read1 <string> <left'>
  406.   DEBUG { (read1 ) print } if
  407.   dup 0 eq {
  408.     pop sectionstr 0 2 put
  409.     stream /Length2 oget
  410.             % Determine whether to hexify data for eexec.
  411.     dup 8 lt {
  412.       type1read2    % Hexify.
  413.     } {
  414.       DEBUG { (read2 ) print } if
  415.       pfbhdr 0 get 16#80 eq {
  416.         % eat 6 more bytes of PFB junk before proceeding
  417.     DEBUG { (skipping PFB header in segment 2) = flush } if
  418.     buffer 0 6 getinterval type1readdata exch
  419.         dup 5 get 256 mul 1 index 4 get add 256 mul
  420.     1 index 3 get add 256 mul 1 index 2 get add
  421.         DEBUG { (PFB segment length = ) print dup = } if
  422.     exch pop  % discard the string keeping the PFB segment length
  423.     2 copy ne {
  424.           (\n   **** Warning: Type 1 PFB segment length and Length 2 value do not match.)
  425.           pdfformaterror
  426.       dup =
  427.       exch         % keep the PFB length instead
  428.     } if
  429.       pop
  430.       } if
  431.       buffer2 type1readdata exch
  432.             % The check doesn't have to be 100% accurate:
  433.             % hexifying is always OK.
  434.       dup 0 8 getinterval 0 exch { or } forall
  435.       128 ge {
  436.     /hexify { } store
  437.     /buffer2 buffer def    % We don't need an intermediate buffer.
  438.       } if hexify exch
  439.     } ifelse
  440.   } {
  441.     buffer type1readdata
  442.   } ifelse
  443. } bdef
  444.  
  445. % Convert a string from binary to hex for eexec.
  446. % Free variables: buffer.
  447. /buf2hex {        % <string> buf2hex <hexstring>
  448.   buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
  449.   buffer (>) search pop exch pop exch pop
  450. } bdef
  451.  
  452. % Read the next block of the encrypted portion.
  453. /type1trailer
  454. (0000000000000000000000000000000000000000000000000000000000000000\n\
  455. 0000000000000000000000000000000000000000000000000000000000000000\n\
  456. 0000000000000000000000000000000000000000000000000000000000000000\n\
  457. 0000000000000000000000000000000000000000000000000000000000000000\n\
  458. 0000000000000000000000000000000000000000000000000000000000000000\n\
  459. 0000000000000000000000000000000000000000000000000000000000000000\n\
  460. 0000000000000000000000000000000000000000000000000000000000000000\n\
  461. 0000000000000000000000000000000000000000000000000000000000000000\n\
  462. cleartomark\n)
  463. readonly def
  464. /type1read2 {        % <left> type1read2 <string> <left'>
  465.   DEBUG { (read2 ) print } if
  466.    dup 0 eq
  467.     { pop sectionstr 0 3 put
  468.       stream /Length3 oget
  469.       dup 0 eq
  470.        { DEBUG { (trailer ) print } if
  471.      type1trailer exch
  472.        }
  473.        { 
  474.          pfbhdr 0 get 16#80 eq {
  475.            % eat 6 more bytes of PFB junk before proceeding
  476.        DEBUG { (skipping PFB header in segment 3) = flush } if
  477.        buffer 0 6 getinterval type1readdata exch
  478.            dup 5 get 256 mul 1 index 4 get add 256 mul
  479.        1 index 3 get add 256 mul 1 index 2 get add
  480.            DEBUG { (PFB segment length = ) print dup = } if
  481.        exch pop  % discard the string keeping the PFB segment length
  482.        2 copy ne {
  483.            (\n   **** Warning: Type 1 PFB segment length and Length 3 value do not match.)
  484.            pdfformaterror
  485.          exch     % keep the PFB length instead
  486.        } if
  487.        pop
  488.        (\n) pdfformaterror
  489.          } if
  490.          type1read3
  491.        }
  492.       ifelse
  493.     }
  494.     { buffer2 type1readdata exch hexify exch
  495.     }
  496.    ifelse
  497. } bdef
  498.  
  499. % Read the next block of the final text portion.
  500. % When finished, this procedure returns an empty string.
  501. /type1read3        % <left> type1read3 <string> <left'>
  502.  { DEBUG { (read3 ) print } if
  503.    buffer type1readdata
  504.  } bdef
  505.  
  506. % ---------------- Type 3 fonts ---------------- %
  507.  
  508. /.notdefEncoding 256 { /.notdef } repeat 256 packedarray def
  509.  
  510. /buildType3 {        % <Type3-font-resource> buildType3 <font>
  511.   8 dict begin
  512.     /FontType 3 def
  513.     /Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def
  514.     /FontBBox 1 index /FontBBox get cvx def
  515.     /FontMatrix 1 index /FontMatrix oget def
  516.     /CharProcs 1 index /CharProcs oget def
  517.     1 index /Widths knownoget {
  518.       /Widths exch def
  519.       /FirstChar 1 index /FirstChar oget def
  520.       /LastChar 1 index /LastChar oget def
  521.     } if
  522.     /FontName 1 index /Name get genfontname def
  523.     /Encoding .notdefEncoding 2 index getencoding def
  524.         % We have to define BuildChar rather than BuildGlyph:
  525.         % there is no PDF equivalent of glyphshow, and we need
  526.         % the character code to access the Widths.
  527.     /BuildChar {
  528.         % Stack: font charcode
  529.       1 index begin 3 dict begin
  530.       /Font 3 -1 roll def /CharCode 1 index def
  531.       % Make unknown characters map to /.notdef
  532.       Encoding exch get dup CharProcs exch known
  533.         { CharProcs exch oget }
  534.     { pop CharProcs /.notdef oget }
  535.       ifelse
  536.       PDFfile fileposition exch
  537.       false resolvestream
  538.         % Stack: filepos stream
  539.         % Don't let setgcolor set the color inside the BuildGlyph
  540.         % procedure, because this causes an /undefined error.
  541.       q null /FillColor gput null /StrokeColor gput
  542.       Font /Resources get exch pdfopdict .pdfruncontext
  543.       Q
  544.       PDFfile exch setfileposition
  545.       end end
  546.     } bdef
  547.     FontName currentdict end definefont exch pop
  548. } bdef
  549. /.adjustcharwidth {    % <wx> <wy> .adjustcharwidth <wx'> <wy'>
  550.   /Widths where {
  551.     begin
  552.     CharCode FirstChar ge CharCode LastChar le and {
  553.       exch pop Widths CharCode FirstChar sub get exch
  554.     } if end
  555.   } if
  556. } bdef
  557.  
  558. % ---------------- TrueType fonts ---------------- %
  559.  
  560. /TTfonts mark
  561.   /Arial /Helvetica
  562.   /Arial,Italic /Helvetica-Oblique
  563.   /Arial,Bold /Helvetica-Bold
  564.   /Arial,BoldItalic /Helvetica-BoldOblique
  565.   /CourierNew /Courier
  566.   /CourierNew,Bold /Courier-Bold
  567.   /TimesNewRoman /Times-Roman
  568.   /TimesNewRoman,Italic /Times-Italic
  569.   /TimesNewRoman,Bold /Times-Bold
  570.   /TimesNewRoman,BoldItalic /Times-BoldItalic
  571. .dicttomark readonly def
  572.  
  573. /buildTrueType {    % <TrueType-font-resource> buildTrueType <font>
  574.   dup /BaseFont get
  575.   dup TTfonts exch .knownget {
  576.     exch pop
  577.         % Hack required by the PDF specification: if the
  578.         % font resource has Subtype = /TrueType but the actual
  579.         % (installed) font is not a TrueType font, ignore the
  580.         % Encoding in the font resource.  However, all current
  581.         % versions of Acrobat Reader have the 14 base TrueType
  582.         % fonts built in, so this produces incorrect output for
  583.         % badly designed PDF files that specify these file names
  584.         % with /Subtype = /TrueType but no embedded definition.
  585.         % Compensate for this by removing the /Subtype key when
  586.         % looking up the font.
  587.     exch dup length dict copy dup /Subtype null put exch
  588.   } if pdffindfont
  589. } bdef
  590.  
  591. % Read an embedded TrueType font.
  592. /readtruetype {        % <font-resource> <stream-dict> readtruetype <font>
  593.         % This is much simpler than readtype1, because we don't
  594.         % have to deal with the tripartite .PFB format.
  595.   1 index exch
  596.   PDFfile fileposition 3 1 roll
  597.   true resolvestream readfontfilter
  598.         % Stack: filepos fontres stream
  599.   1 index /Subtype get /CIDFontType2 eq {
  600.     .loadttcidfont
  601.         % Stack: filepos fontres cidfont
  602.     1 index /CIDToGIDMap knownoget {
  603.       dup /Identity eq {
  604.     pop
  605.       } {
  606.     true resolvestream
  607.         % The following doesn't work for CIDToGIDMaps with more
  608.         % than 32K-1 entries.  We'll fix it later if necessary.
  609.         % Stack: filepos fontres font mapstream
  610.     dup 2 index /CIDCount oget 2 mul string readstring pop exch closefile
  611.     exch dup length 5 add dict .copydict
  612.     dup /FID undef
  613.     dup /CIDMap 4 -1 roll put
  614.     dup /CIDFontName get exch /CIDFont defineresource
  615.       } ifelse
  616.     } if
  617.   } {
  618.     null 2 index getencoding .loadpdfttfont
  619.   } ifelse
  620.   exch pop
  621.   PDFfile 3 -1 roll setfileposition
  622.         % Ignore both the Encoding and the Widths.
  623.   exch pop
  624. } bdef
  625.  
  626. % ---------------- Type 0 fonts ---------------- %
  627.  
  628. % Predefine the known CMaps, but only create them on demand.
  629. /knownCMaps mark
  630.   /Identity-H { /Identity-H 0 makeIdentityCMap }
  631.   /Identity-V { /Identity-V 1 makeIdentityCMap }
  632. .dicttomark def
  633.  
  634. /makeIdentityCMap {        % <cmapname> <wmode> .makeIdentityCMap -
  635.   .currentglobal true .setglobal 3 1 roll
  636.   /CIDInit /ProcSet findresource begin
  637.   12 dict begin
  638.     begincmap
  639.     /WMode exch def
  640.     /CMapName exch def
  641.     /CIDSystemInfo 3 dict dup begin
  642.       /Registry (Adobe) def
  643.       /Ordering (Identity) def
  644.       /Supplement 0 def
  645.     end def
  646.     %/CMapName (see above)
  647.     /CMapVersion 1 def
  648.     /CMapType 1 def
  649.     %WMode (see above)
  650.     % The PDF documentation says that these CMaps map CIDs
  651.     % "1 to 65,536".  This is a misprint for 0 to 65,535.
  652.     1 begincodespacerange
  653.     % <0001> <00ff>  <0100> <ffff>
  654.       <0000> <ffff>
  655.     endcodespacerange
  656.     1 begincidrange
  657.     % <0001> <00ff> 1   <0100> <ffff> 256
  658.       <0000> <ffff> 0
  659.     endcidrange
  660.     endcmap
  661.     CMapName currentdict /CMap defineresource
  662.     knownCMaps CMapName 2 index put
  663.   end        % CMap
  664.   end        % CIDInit ProcSet
  665.   exch .setglobal
  666. } bdef
  667.  
  668. /buildType0 {        % <Type0-font-resource> buildType0 <font>
  669.   dup /BaseFont get    % FontName
  670.   1 index /Encoding oget
  671.   dup type /nametype eq {
  672.     dup /CMap resourcestatus {
  673.     pop pop /CMap findresource
  674.     } {
  675.     knownCMaps 1 index .knownget
  676.       { exch pop exec } { /undefined signalerror } ifelse
  677.     } ifelse
  678.   } {
  679.     PDFfile fileposition exch
  680.     dup /CMapName get exch true resolvestream cvx exec
  681.     /CMap findresource
  682.     exch PDFfile exch setfileposition
  683.   } ifelse        % CMap
  684.   [
  685.     3 index /DescendantFonts oget { exec resourcefont } forall
  686.   ]            % subfonts
  687.   composefont
  688.         % Stack: fontres font
  689.   1 index /FontMatrix knownoget {
  690.     dup aload pop true {0 0 1 0 0 1} {3 -1 roll eq and} forall {
  691.       1 index exch makefont exch /FontName get exch definefont
  692.     } {
  693.       pop
  694.     } ifelse
  695.   } if exch pop
  696. } bdef
  697.  
  698. % ---------------- CIDFontType0/2 fonts ---------------- %
  699.  
  700. % Insert metrics into a CIDFont, by saving the PDF W, W2, DW, and DW2
  701. % arrays and using a (currently very inefficient) CDevProc.
  702. /addCIDmetrics {    % <CIDFont-resource> <CIDFont> addCIDmetrics <fontdict>
  703.   dup length 5 add dict .copydict
  704.   dup /FID undef
  705.   dup /UniqueID undef
  706.   dup /XUID undef
  707.     % Insert the widths into the font.
  708.   {W W2 DW DW2} {
  709.     % Stack: pdfresource newfont key
  710.     2 index 1 index .knownget {
  711.       2 index 3 1 roll put
  712.     } {
  713.       pop
  714.     } ifelse
  715.   } forall
  716.   dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put
  717.   exch pop
  718. } bdef
  719.  
  720. % Apply the [D]W[2] metrics to a character before displaying.
  721. /CIDWProc {        % <w0x> <w0y> <llx> <lly> <urx> <ury>
  722.             %   <w1x> <w1y> <vx> <vy> <cid> <font> CIDWproc
  723.             %   <w0x'> ... <vy'>
  724.   begin
  725.     % Look up and apply [D]W
  726.   10 index
  727.   currentdict /DW .knownget { 1000 div exch pop } if
  728.   currentdict /W .knownget {
  729.     % Search the W array for the CID.
  730.     % ****** NOT IMPLEMENTED YET ******
  731.     pop
  732.   } if
  733.   0 13 2 roll 11 -2 roll pop pop
  734.     % Look up and apply [D]W2
  735.     % ****** NOT IMPLEMENTED YET ******
  736.   pop end
  737. } bdef
  738. % <string> <match> tailmatch ==> <pre> true
  739. %                            ==> <string> false
  740. /tailmatch {
  741.   2 copy length 1 index length min
  742.   dup 2 index length exch sub exch getinterval
  743.   1 index eq {
  744.     length 1 index length exch sub
  745.     0 exch getinterval true
  746.   } {
  747.     pop false
  748.   } ifelse
  749. } bind def
  750.  
  751. /makeboldfont {
  752.   16 dict begin
  753.     /strokewidth exch def
  754.     /basecidfont exch def
  755.     /FontMatrix [ 1 0 0 1 0 0 ] def
  756.  
  757.     /CIDFontName /.boldfont def
  758.     /CIDFontType 1 def
  759.  
  760.     /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def
  761.     /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def
  762.  
  763.     /CIDSystemInfo dup basecidfont exch get def
  764.     /FontBBox [ basecidfont /FontBBox get cvx exec
  765.       4 2 roll basecidfont /FontMatrix get transform
  766.       4 2 roll basecidfont /FontMatrix get transform
  767.     ] def
  768.  
  769.     /tmpstr 2 string def
  770.     /BuildGlyph {
  771.       gsave
  772.       exch begin
  773.         dup 256 idiv tmpstr exch 0 exch put
  774.         256 mod tmpstr exch 1 exch put
  775.         rootfont /WMode known { rootfont /WMode get 1 eq } { false } ifelse
  776.         { basefont-V } { basefont-H } ifelse setfont
  777.         strokewidth setlinewidth
  778.         1 setlinejoin
  779.         newpath
  780.         0 0 moveto tmpstr false charpath stroke
  781.         0 0 moveto tmpstr show
  782.         currentpoint setcharwidth
  783.       end
  784.       grestore
  785.     } bind def
  786.  
  787.    currentdict
  788.   end
  789.   dup /CIDFontName get exch /CIDFont defineresource
  790. } bind def
  791.  
  792. % <CIDFont-resource> <CIDFontName> findCIDFont <CIDFont-resource> <font>
  793. %   CIDFont-resource is not modified.
  794. /findCIDFont {
  795.   {
  796.     dup /CIDFont resourcestatus {
  797.       pop pop /CIDFont findresource
  798.       exit
  799.     } if
  800.  
  801.     dup dup length string cvs
  802.     (,Bold) tailmatch {
  803.       exch pop
  804.       cvn findCIDFont 0.03 makeboldfont
  805.       exit
  806.     } if
  807.     (,Italic) tailmatch {
  808.       exch pop
  809.       cvn findCIDFont
  810.       [ 1 0 0.3 1 0 0 ] makefont
  811.       exit
  812.     } if
  813.     (,BoldItalic) tailmatch {
  814.       exch pop
  815.       cvn findCIDFont 0.03 makeboldfont
  816.       [ 1 0 0.3 1 0 0 ] makefont
  817.       exit
  818.     } if
  819.     pop
  820.  
  821.     1 index /CIDSystemInfo get begin Registry (-) Ordering end
  822.     concatstrings concatstrings
  823.     cvn
  824.     QUIET not {
  825.       (Substituting ) print dup ==only
  826.       ( for ) print 1 index ==only (.\n) print
  827.     } if
  828.     exch pop
  829.     /CIDFont findresource
  830.     exit
  831.   } loop
  832. } bdef
  833.  
  834. /buildCIDType0 {    % <CIDFontType0-font-resource> buildCIDType0 <font>
  835.   dup /BaseFont get exch 1 index findCIDFont
  836.   addCIDmetrics /CIDFont defineresource
  837. } bdef
  838.  
  839. /buildCIDType2 {    % <CIDFontType2-font-resource> buildCIDType2 <font>
  840.   dup /BaseFont get exch 1 index findCIDFont
  841.   addCIDmetrics /CIDFont defineresource
  842. } bdef
  843.  
  844. % ---------------- Other embedded fonts ---------------- %
  845.  
  846. /fontloadprocs mark
  847.   /Type1C /readType1C cvx
  848.   /CIDFontType0C /readCIDFontType0C cvx
  849. .dicttomark readonly def
  850.  
  851. % Read an embedded compressed font.
  852. /readType1C {        % <font-resource> <stream-dict> readType1C <font>
  853.   1 index exch
  854.   PDFfile fileposition 3 1 roll
  855.   dup true resolvestream dup readfontfilter
  856.         % Stack: pos resource streamdict stream filter
  857.   3 index /FontDescriptor oget /FontName oget
  858.   1 index FRD
  859.   closefile closefile pop
  860.   PDFfile 3 -1 roll setfileposition
  861.   /FontDescriptor oget /FontName oget findfont
  862.   adjustfont
  863. } bdef
  864.  
  865. % Read an embedded CFF CIDFont.
  866. /readCIDFontType0C {  % <font-resource> <stream-dict> readCIDFontType0C <font>
  867.   PDFfile fileposition 3 1 roll
  868.   dup true resolvestream dup readfontfilter
  869.         % Stack: pos resource streamdict stream filter
  870.   3 index /FontDescriptor oget /FontName oget
  871.   1 index FRD
  872.   closefile closefile pop
  873.   PDFfile 3 -1 roll setfileposition
  874.         % Some broken Adobe software produces PDF files in which
  875.         % the FontName of the CFF font and the FontName in the
  876.         % FontDescriptor don't match the BaseFont in the font.
  877.         % Use the FontName, rather than the BaseFont, here.
  878.   dup /FontDescriptor oget /FontName oget /CIDFont findresource
  879.   addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
  880. } bdef
  881.  
  882. % ---------------- Font lookup ---------------- %
  883.  
  884. /fonttypeprocs mark        % <font-resource> -proc- <font>
  885.   /Type0 /buildType0 cvx
  886.   /Type1 /buildType1 cvx
  887.   /MMType1 1 index
  888.   /Type3 /buildType3 cvx
  889.   /TrueType /buildTrueType cvx
  890.   /CIDFontType0 /buildCIDType0 cvx
  891.   /CIDFontType2 /buildCIDType2 cvx
  892. .dicttomark readonly def
  893.  
  894. /resourcefont            % <font-resource> resourcefont <font>
  895.  { dup /PSFont .knownget
  896.     { /FID .knownget { type /fonttype eq } { false } ifelse }
  897.     { false }
  898.    ifelse
  899.     { /PSFont get
  900.     }
  901.     { dup dup /FontDescriptor knownoget
  902.        {    % Stack: font-res font-res font-desc
  903.      dup /FontFile knownoget
  904.       { exch pop readtype1 true }
  905.       { dup /FontFile2 knownoget
  906.          { exch pop readtruetype true }
  907.          { /FontFile3 knownoget
  908.         { dup /Subtype get fontloadprocs exch get exec true }
  909.         { false }
  910.            ifelse
  911.          }
  912.         ifelse
  913.       }
  914.      ifelse
  915.        }
  916.        { false }
  917.       ifelse
  918.         % Stack: font-res font-res false
  919.         %  -or-: font-res font true
  920.       not
  921.        { dup /Subtype get fonttypeprocs exch get exec }
  922.       if
  923.       2 copy /PSFont exch put
  924.       exch pop
  925.     }
  926.    ifelse
  927.  } bdef
  928.  
  929. drawopdict begin
  930.   /d0 {
  931.     .adjustcharwidth setcharwidth
  932.   } bdef
  933.   /d1 {
  934.     6 -2 roll .adjustcharwidth 6 2 roll setcachedevice
  935.   } bdef
  936.   /Tf {
  937.     1 index Page /Font rget not { 1 index /invalidfont signalerror } if
  938.     resourcefont exch Tf pop
  939.   } bdef
  940. end
  941.  
  942. end            % pdfdict
  943. end            % GS_PDF_ProcSet
  944. .setglobal
  945.